package heliotrope.display
{
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import heliotrope.utils.CompassDirection;
	
	import org.hamcrest.object.nullValue;

	/**
	 * 显示对象的基类
	 * 继承自Sprite，实现了注册点的设置
	 * 注册点解释：图像在移动，放大，旋转等操作时的原点（中心点） 
	 * */
	public class RegSprite extends Sprite
	{
		private var _regPoint:Point = new Point(0,0);//注册点坐标，相对于左上角
		private var _regPos:CompassDirection = null;//注册位置，当手动设置注册点时，此值失效
		private var _regable:Boolean = false;
		private var _dispContent:Sprite;
		/**
		 *创建RegSprite对象，并设置注册点，注册位置，内容
		 * @param regSet 显示对象注册点的设置，可接受注册位置信息（RegPos:String）或者实际的点坐标
		 * 注册位置解释：注册位置提供了一个相对的注册概念，例如注册点处在图像的中心，亦或是左上角。
		 * */
		public function RegSprite(regSet_:* = null)
		{
			_dispContent = new Sprite;
			super.addChild(_dispContent);
			this.regPoint = regSet_;
			this.addEventListener(Event.ADDED, refresh);
			this.addEventListener(Event.REMOVED, refresh);
		}

		/**
		 *The regpoint can be setted by Point,Array,CompassDirection.
		 * */
		public function set regPoint(regp:*):void
		{
			if(regp is Point)//传入点对象的情况
			{
				_regable = true;
				_regPos = null;
				_regPoint.copyFrom(regp as Point);
			}
			else if(regp is Array)//传入数组形式坐标的情况
			{
				_regable = true;
				_regPos = null;
				_regPoint.setTo((regp as Array)[0], (regp as Array)[1]);
			}
			else if(regp is CompassDirection)//传入注册位置的情况
			{
				_regable = true;
				_regPos = regp as CompassDirection;
				convPos2Point();//根据注册位置刷新注册点
			}
			else if(!regp)
			{
				_regable = false;
				_regPoint.setTo(0,0);
				_dispContent.x = 0;
				_dispContent.y = 0;		
			}
			else
			{
				throw new Error("setregPoint need only Point、String、Array or Null(for disregable)");
			}
			refresh();
		}
		
		/**
		 *Conert the RegPos to Regpoint
		 * */
		private function convPos2Point():void
		{
			if(_regPos==null)
			{
				return;
			}
			var needHandleMask:Boolean = this.mask!=null&&this.contains(this.mask);
			if(needHandleMask)
			{
				this.removeEventListener(Event.REMOVED, refresh);
				this.removeEventListener(Event.ADDED, refresh);
				_dispContent.removeChild(this.mask);
			}
			var bounds:Rectangle = _dispContent.getBounds(_dispContent);
			if(needHandleMask)
			{
				_dispContent.addChild(this.mask);
				this.addEventListener(Event.ADDED, refresh);
				this.addEventListener(Event.REMOVED, refresh);
			}
			switch(_regPos)//Calculate the regpoint by repposition
			{
				case CompassDirection.NW:
					_regPoint.copyFrom(bounds.topLeft);
					break;
				case CompassDirection.N:
					_regPoint.setTo(bounds.width/2+bounds.x, bounds.y);
					break;
				case CompassDirection.NE:
					_regPoint.setTo(bounds.right, bounds.y);
					break;
				case CompassDirection.E:
					_regPoint.setTo(bounds.right, bounds.height/2+bounds.y);
					break;
				case CompassDirection.SE:
					_regPoint.copyFrom(bounds.bottomRight);
					break;
				case CompassDirection.S:
					_regPoint.setTo(bounds.width/2+bounds.x, bounds.bottom);
					break;
				case CompassDirection.SW:
					_regPoint.setTo(bounds.x, bounds.bottom);
					break;
				case CompassDirection.W:
					_regPoint.setTo(bounds.x, bounds.height/2+bounds.y);
					break;
				case CompassDirection.CENTER:
					_regPoint.setTo(bounds.width/2+bounds.x, bounds.height/2+bounds.y);
					break;
			}
		}
		
		/**
		 *Refresh the regpoint with current content.
		 * */	
		public function refresh(...args):void
		{
			if(_regable)
			{
				convPos2Point();
				_dispContent.x = -_regPoint.x;
				_dispContent.y = -_regPoint.y;	
			}
		}
		
		public function get regPoint():Point{return regPoint;}
		
		public function set ox(value_:Number):void{_regPoint.x = value_;refresh();}
		public function get ox():Number{return _regPoint.x;}
		
		public function set oy(value_:Number):void{_regPoint.y = value_;refresh();}
		public function get oy():Number{return _regPoint.y;}	
		
		public function get content():Sprite{return _dispContent;}
		
		//========
		// Override methods below, _dispContent as a proxy.
		
		override public function set width(value_:Number):void{_dispContent.width = value_;refresh();}
		
		override public function set height(value_:Number):void{_dispContent.height = value_;refresh();}
		
		override public function set scaleX(value_:Number):void{_dispContent.scaleX = value_;refresh();}
		
		override public function set scaleY(value_:Number):void{_dispContent.scaleY = value_;refresh();}
		
		override public function get graphics():Graphics{this.addEventListener(Event.RENDER, dirtyRender);return _dispContent.graphics;}
		protected function dirtyRender(event_:Event):void{this.removeEventListener(Event.RENDER, dirtyRender);refresh();}
		
		override public function addChild(child:DisplayObject):DisplayObject{_dispContent.addChild(child);return child;}
		
		override public function addChildAt(child:DisplayObject, index:int):DisplayObject{_dispContent.addChildAt(child, index);return child;}
		
		override public function getChildAt(index:int):DisplayObject{return _dispContent.getChildAt(index);}
		
		override public function getChildByName(name:String):DisplayObject{return _dispContent.getChildByName(name);}
		
		override public function getChildIndex(child:DisplayObject):int{return _dispContent.getChildIndex(child);}
		
		override public function removeChild(child:DisplayObject):DisplayObject{_dispContent.removeChild(child);return child;}
		
		override public function removeChildAt(index:int):DisplayObject{var child:DisplayObject = _dispContent.removeChildAt(index);return child;}
		
		override public function setChildIndex(child:DisplayObject, index:int):void{_dispContent.setChildIndex(child, index);}
		
		override public function swapChildren(child1:DisplayObject, child2:DisplayObject):void{_dispContent.swapChildren(child1, child2);}
		
		override public function swapChildrenAt(index1:int, index2:int):void{_dispContent.swapChildrenAt(index1, index2);}	
		//========
	}
}